You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
//Get rid of PLAY audio requests when pausing audio.
std::list<AudioRequest*>::iterator ait;
for (ait = m_audioRequests.begin(); ait != m_audioRequests.end(); /* empty */)
{
AudioRequest *req = (*ait);
if( req && req->m_request == AR_Play )
{
deleteInstance(req);
ait = m_audioRequests.erase(ait);
}
else
{
ait++;
}
}
AudioRequest::m_pendingEvent can be an owning raw pointer, though, which the destructor of AudioRequest should delete when needed. It currently doesn't, which is why the leak happens.
Caball009
added
Minor
Severity: Minor < Major < Critical < Blocker
Gen
Relates to Generals
ZH
Relates to Zero Hour
Memory
Is memory related
Fix
Is fixing something, but is not user facing
labels
May 19, 2026
This PR fixes a memory leak that occurred when pausing the game while audio play requests were queued. The leak happened because AudioRequest::~AudioRequest() did not delete m_pendingEvent, and any queued AR_Play requests discarded at pause time left their AudioEventRTS* dangling.
AudioRequest.cpp: Adds a destructor body that deletes m_pendingEvent when m_usePendingEvent is true, covering the pause-discard path and any other path that destroys a play request before processing it (e.g., checkForSample failures).
MilesAudioManager.h/.cpp: Changes playAudioEvent to accept AudioEventRTS*& (reference to pointer) so it can null out the caller's pointer immediately after transferring ownership to PlayingAudio::m_audioEventRTS, preventing the destructor from double-deleting an already-owned event on the normal play path.
Confidence Score: 5/5
The change is a well-scoped memory leak fix with no behavioural side effects on the normal play path.
Ownership transfer is handled correctly in all three audio branches (stream, 3D, 2D). The early-return path in playAudioEvent when getAudioEventInfo() returns null leaves the pointer non-null, but the destructor then correctly deletes it. The delete nullptr on the normal play path is defined no-op behaviour in C++. The m_usePendingEvent guard properly prevents the destructor from misinterpreting the union as a pointer for pause/stop requests.
Adds destructor body that correctly deletes m_pendingEvent when m_usePendingEvent is true; delete nullptr is safe in C++ for the normal-play path where ownership was already transferred.
Implements the reference-to-pointer signature; all three audio branches (stream, 3D, 2D) null out the event pointer immediately after assigning to audio->m_audioEventRTS, and downstream uses are correctly switched to audio->m_audioEventRTS.
Sequence Diagram
sequenceDiagram
participant PL as processRequestList
participant PR as processRequest
participant PA as playAudioEvent
participant AR as ~AudioRequest
Note over PL: Normal play path
PL->>PR: processRequest(req)
PR->>PA: "playAudioEvent(req->m_pendingEvent)"
PA->>PA: "audio->m_audioEventRTS = event"
PA->>PA: "event = nullptr (nulls req->m_pendingEvent)"
PA-->>PR: return
PR-->>PL: return
PL->>AR: deleteInstance(req)
AR->>AR: "m_usePendingEvent=true, m_pendingEvent=nullptr"
AR->>AR: delete nullptr (no-op, safe)
Note over PL: Pause / discard path
PL->>AR: deleteInstance(req) [skips processRequest]
AR->>AR: "m_usePendingEvent=true, m_pendingEvent!=nullptr"
AR->>AR: delete m_pendingEvent (leak fixed!)
Rebased to include the fix for the CI Replay checker.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FixIs fixing something, but is not user facingGenRelates to GeneralsMemoryIs memory relatedMinorSeverity: Minor < Major < Critical < BlockerZHRelates to Zero Hour
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pausing the game leaks audio events that were in the audio request container at the time. This PR fixes that.
This code is called to get rid of some of the audio requests when pausing the game:
GeneralsGameCode/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp
Lines 587 to 601 in 2219f63
AudioRequest::m_pendingEventcan be an owning raw pointer, though, which the destructor ofAudioRequestshould delete when needed. It currently doesn't, which is why the leak happens.GeneralsGameCode/Core/GameEngine/Include/Common/AudioRequest.h
Line 51 in 2219f63
There's one exception where the ownership of the audio event is taken away from the audio request:
GeneralsGameCode/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp
Line 2238 in 2219f63